home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
026-050
/
scopedisk28
/
getfil
/
getfile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-18
|
16KB
|
660 lines
/* getfile.c */
/* This file contains a general-purpose 'requester' that
will prompt the user for a filename input.
The program actually uses a window instead of a 'Requester'
for greater flexibility. It will take control of your window's
IDCMP Port when called.
This code borrows from several sources, but has been EXTENSIVELY
revised (read improved, cleaned up, made readable).
Advantages of this file requester:
1. NO 'Wrong Diskette?' MESSAGE!!!!!!!!
Since The System prompts for a volume if it can't find it,
why rub it in the user's face? If the user selects a path
that does not work, this code will try the previous path
again. If that is also bad, it goes to DF0:, since
everyone has one of those.
2. The 'OK' gadget can have any text you want in it up to
six characters. Try ' OK ', ' LOAD ', ' SAVE '
and the like.
3. Hitting 'Return' while editing the path searches that path.
4. Hitting 'Return' while editing the file name is same as
hitting the 'OK' gadget.
5. Standard device gadgets for df0:, df1:, and dh0:
6. Easy to read, more comments, and variables with names that
have meaning (as opposed to ones like 'kludge', 'oops' etc.)
7. Which means easy to modify. You can add pattern filters and
extra device gadgets (like ram:, vd0:) quite easily.
If you do add gadgets, make sure to account for the 'OK'
gadget text, which currently goes into DrWIText9.IText
Dave Arendash
Escape Velocity, Inc.
405 Rancho Arroyo #264
Fremont, CA 94536
*/
#include "standard.h"
#include "getfile.h"
/* extern struct IntuiMessage *GetMsg(); */
extern char *BrowseDir();
extern char *StartBrowsing();
static struct FileLock *DirPtr = NULL;
static struct FileInfoBlock *dir_info;
static struct Window *ParentWin; /* Parent Window. */
static struct TextAttr DirFont =
{
"topaz.font",
TOPAZ_EIGHTY,FS_NORMAL,FPF_ROMFONT
};
#include "filereq.h"
static struct direntry
{
struct direntry *next;
BOOL isfile;
char text[DSIZE+2];
};
static struct direntry *FirstEntry;
static struct direntry *NextEntry;
static struct dirhead
{
struct direntry *next;
};
static struct dirhead ListHead;
static long CurEntry, TotalEntries;
static BOOL more;
static struct Window *ReqWindow = NULL; /* Requester window */
static struct RastPort *ReqRastPort;
/* Requester "Hailing" prompt */
static struct IntuiText TopIText = {2,2,JAM1,10,11,NULL, NULL ,NULL};
static struct IntuiText DirIText =
{
0,1,JAM2,0,1,
&DirFont,
(UBYTE *)"(dir) ",
NULL
};
static struct IntuiText names[DENTS] =
{
/* File name list */
{2,1,JAM2,48,1,NULL,NULL, NULL},
{2,1,JAM2,48,1,NULL,NULL, NULL},
{2,1,JAM2,48,1,NULL,NULL, NULL},
{2,1,JAM2,48,1,NULL,NULL, NULL},
{2,1,JAM2,48,1,NULL,NULL, NULL}
};
/* Open a requester "Window" */
static struct NewWindow NewFiles =
{
160, 30, REQWIDTH,REQHEIGHT, BCOL,FCOL, NULL, /* Fill in AFTER opening ... */
SMART_REFRESH | ACTIVATE | RMBTRAP | WINDOWDRAG,
&DrWGadgetList1, NULL, NULL, NULL,
NULL, REQWIDTH, REQHEIGHT, REQWIDTH, REQHEIGHT, WBENCHSCREEN
};
static struct IntuiText Note_IText = {0,1,JAM2, 5,20,NULL,NULL, NULL};
static struct IntuiText OK_IText = {0,1,JAM2, 5,3,NULL," OK", NULL};
TEXT *pathtxt;
char *retval;
char *path;
char *name;
char *pddef, *pddir, orgname[MAXSTRINGSIZE], orgpath[MAXSTRINGSIZE];
char temppath[MAXSTRINGSIZE], tempname[MAXSTRINGSIZE];
BOOL OKtoGo;
BOOL dir_flag;
IMPORT struct Library *IntuitionBase;
/* get_fname (window, screen, hail, ddef, ddir, txt);
Displays a window/requester that
gets a file name for device, directory, default file
Calling args:
window: Window making the request
screen: Screen, if NULL assummed workbench
hail: Text at top of requester (may be used as a prompt)
ddef: Input default file-name. Has NO DRIVE OR PATH
ddir: Directory of file, may be null
txt: text for OK button
If the user hits 'Cancel', these won't be
overwritten. If he hits 'OK', they will be overwritten
with the path and filenames which appear in the string
gadgets at that time. Returns 0 if unsuccessful for any
reason.
*/
get_fname (CallWin, screen, hail, ddef, ddir, txt)
struct Window *CallWin; /* Calling Window */
struct Screen *screen; /* screen .... if null assume workbench */
UBYTE *hail; /* Hailing prompt */
char *ddef; /* default probable file-name */
char *ddir; /* default directory in which to search */
char *txt; /* text for OK button, if NULL, uses 'OK' */
{
register struct IntuiMessage *imes; /* Wait for message in here*/
register struct Gadget *igad; /* gadget identifier */
register long i, j, class;
orgname[0] = orgpath[0] = tempname[0] = temppath[0] = 0;
/* copy originals to orgname and orgpath for editing */
strcpy (orgname, ddef);
strcpy (orgpath, ddir);
path = orgpath;
name = orgname;
pddef = ddef;
pddir = ddir;
if (!(ParentWin = CallWin))
return (NULL);
/* set text for OK button */
if (txt)
strcpy (DrWIText9.IText, txt);
else
strcpy (DrWIText9.IText, " OK");
/* Set default file name */
DrWFileNameGadSInfo.Buffer = name;
/* Set default device name */
DrWPathGadSInfo.Buffer = path;
/* clear name structures */
for (i=0; i < DENTS; i++)
{
names[i].IText = "";
names[i].NextText = NULL;
};
NewFiles.Title = ParentWin->Title;
/* get memory for file info operations */
if (!(dir_info = AllocMem ((long)sizeof(struct FileInfoBlock), 0L)))
return (NULL);
/* if user supplied a screen, use it */
if (screen)
{
NewFiles.Type = CUSTOMSCREEN;
NewFiles.Screen = screen;
NewFiles.LeftEdge = (screen->Width - REQWIDTH) >> 1;
NewFiles.TopEdge = (screen->Height - REQHEIGHT) >> 1;
}
/* allocate a heap and open the window */
if (!(FirstEntry = (struct direntry *)AllocMem ((long)DBUFSIZ,0L)) ||
!(ReqWindow = (struct Window *)OpenWindow (&NewFiles)))
{
if (FirstEntry)
FreeMem (FirstEntry,(long)DBUFSIZ);
/* notify (ReqWindow,"Can't Open Requester..."); */
FreeMem (dir_info, (long)sizeof (struct FileInfoBlock));
return (NULL);
}
/* Set up directory */
Path();
/* This optional line will activate a string gadget */
if (IntuitionBase->lib_Version > 32)
ActivateGadget (&DrWFileNameGad,ReqWindow,0L);
ReqRastPort = ReqWindow->RPort;
/* set up the message port */
ReqWindow->UserPort = ParentWin->UserPort;
ModifyIDCMP (ReqWindow, (long)MOUSEBUTTONS | (long)GADGETDOWN |
(long)GADGETUP | (long)MOUSEMOVE);
/* paint background color of requester */
SetAPen (ReqRastPort,1L);
RectFill (ReqRastPort,4L,10L,(long)(NewFiles.Width-5),
(long)(NewFiles.Height-4));
/* put hailing text on screen */
TopIText.IText = hail;
TopIText.LeftEdge = (REQWIDTH - IntuiTextLength(&TopIText)) >> 1L;
PrintIText (ReqRastPort, &TopIText, 0L, 0L);
/* put all gadgets on screen */
RefreshGadgets (&DrWOKGad, ReqWindow, 0L);
/* assume all ok */
OKtoGo = 1;
/* do until OK, Cancel, or bad error */
while (OKtoGo)
{
while (!(imes = GetMsg (ReqWindow->UserPort)))
{
/* if displayed directory list needs updating... */
if (dir_flag)
{
/* determine index of first displayed name */
i = (long)(TotalEntries - DENTS) *
(j = (long)DrWDirPropGadSInfo.VertPot) /
(long)MAXBODY;
if (i > (TotalEntries - DENTS))
i = TotalEntries - DENTS;
if (i < 0L)
i = 0L;
CurEntry = i;
/* display what we have to date */
DispDir();
dir_flag = 0;
}
/* if more entries to be read, read them; otherwise
wait for user to do something */
if (more)
{
/* read them, or say why we can't */
if (pathtxt = (char *)BrowseDir())
notify (ReqWindow, pathtxt);
if (TotalEntries <= DENTS)
dir_flag = TRUE;
}
else
WaitPort (ReqWindow->UserPort);
}
/* interpret user interaction message */
igad = (struct Gadget *)imes->IAddress;
class = imes->Class;
ReplyMsg (imes);
switch (class)
{
case MOUSEMOVE:
/* user is scrolling, flag a re-display */
dir_flag = TRUE;
case GADGETUP:
case GADGETDOWN:
/* a gadget activated */
HandleEvent (igad);
break;
}
}
/* clean up memory */
FreeMem (FirstEntry, (long)DBUFSIZ);
FreeMem (dir_info, (long)sizeof (struct FileInfoBlock));
/* clean up after disk access */
free_DirPtr ();
CloseWindowSafely (ReqWindow);
return (1);
}
/* used when user clicks on a directory entry in the displayed list */
DirEnt (gad)
struct Gadget *gad; /* one of the DENTS gadgets containing names */
{
short i, dirent;
dirent = gad->GadgetID - (short)DIR_ENT1;
/* Replace file or directory name */
pathtxt = names[dirent].IText;
/* if filename */
if (names[dirent].NextText == NULL)
{
/* update the file name editing gadget */
RemoveGadget (ReqWindow,&DrWFileNameGad);
for (i = 0; i < DSIZE; i++)
name[i] = *pathtxt++;
AddGadget (ReqWindow, &DrWFileNameGad, -1L);
RefreshGadgets (&DrWFileNameGad, ReqWindow, 0L);
}
else
{
/* else dir name */
/* update the path name editing gadget */
RemoveGadget (ReqWindow, &DrWPathGad);
pathcat (path, pathtxt);
*DrWFileNameGad.SpecialInfo.Buffer = 0;
AddGadget (ReqWindow, &DrWPathGad, -1L);
RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
}
/* update displayed list as needed */
Path();
}
/* various gadgets hit (selected), replace paths with these defaults */
DF0Hit ()
{
strcpy (path, "df0:");
RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
Path();
}
DF1Hit ()
{
strcpy (path, "df1:");
RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
Path();
}
DH0Hit ()
{
strcpy (path, "dh0:");
RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
Path();
}
/* read the disk for entries on this path */
/* called when user presses 'Return' when editing path name, and whenever
we want to read a directory */
Path ()
{
/* try the chosen path */
if (!StartBrowsing (path))
/* good new directory, clear the file name */
*DrWFileNameGad.SpecialInfo.Buffer = 0;
else
{
/* something wrong with new directory, restore old */
strcpy (name, tempname);
strcpy (path, temppath);
RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
/* this old directory may also now be invalid
(if user has removed the disk, for instance.
The System has alread asked him about this by now */
if (!StartBrowsing (path))
{
/* if all else fails, EVERYONE HAS A DRIVE DF0:! */
strcpy (path, "df0:");
RefreshGadgets (&DrWPathGad, ReqWindow, 0L);
StartBrowsing (path);
}
}
dir_flag = TRUE;
}
/* called when the directory proportional gadget is moved */
DirProp ()
{
/* user scrolling, flag for re-display */
dir_flag = TRUE;
}
/* called when user presses 'Return' when editing file name */
FileName ()
{
/* Name gadget, 'Return' pressed assumes same as hitting OK gadget */
retval = name;
OKHit();
}
OKHit()
{
/* OK gadget */
retval = name;
/* return the edited name and path */
strcpy (pddef, orgname);
strcpy (pddir, orgpath);
/* flag to exit requester */
CancelHit();
}
CancelHit()
{
/* flag to exit requester */
OKtoGo = FALSE;
}
/* clean up after disk access */
static free_DirPtr()
{
if (DirPtr)
{
UnLock (DirPtr);
DirPtr = NULL;
}
}
/*
StartBrowsing ()
Initialize the file info block for directory access. Null return
is good, else return is a pointer to an error string */
static char *StartBrowsing (subdir)
char *subdir;
{
more = FALSE;
CurEntry = TotalEntries = 0;
NextEntry = FirstEntry; /* Allocate from here */
ListHead.next = NULL; /* Clear the list */
free_DirPtr(); /* Unlock any old lock */
/* lock this directory so it can't be deleted while we're here */
DirPtr = (struct FileLock *)Lock (subdir, (ULONG)ACCESS_READ);
/* if file not found, or couldn't read directory, or is a file... */
if (!DirPtr || !Examine (DirPtr, dir_info) ||
(dir_info->fib_DirEntryType < 0L ))
{
dir_flag = 1;
return ("Could not read disk");
}
/* got a good path, remember where it is */
strcpy (tempname, name);
strcpy (temppath, path);
more = TRUE;
return (BrowseDir());
}
/* read directory entries and put them in the list to be displayed */
static char *BrowseDir()
{
register struct direntry *TmpDir = NextEntry;
register struct direntry *ThisPtr = (struct direntry *)&ListHead;
register struct direntry *NextPtr;
register TEXT *tmpstr;
register long i;
if (!more)
return (NULL);
/* if there is any entries we haven't read yet, read another... */
if (ExNext (DirPtr, dir_info))
{
/* run out of heap space? */
if ((ULONG)TmpDir >=
((ULONG)FirstEntry + (ULONG)DBUFSIZ -
(ULONG)sizeof (struct direntry)))
{
more = FALSE;
return ("Directory Truncated");
}
/*******************************************************
Here you can add a file/directory filter and/or
pattern matching filter(s). You will probably also
want to add this pattern format string to the parameter
list passed to get_fname()
*******************************************************/
/* filename text string is at &TmpDir->text[0] */
/* set file type flag */
TmpDir->isfile = (dir_info->fib_DirEntryType < 0L);
/* copy the name from the file info block just read */
tmpstr = &TmpDir->text[0];
for (i=0; i < FCHARS; i++)
if (!(*tmpstr++ = dir_info->fib_FileName[i]))
break;
*tmpstr = 0;
/* move down in heap, long word align */
i = (long)tmpstr;
NextEntry = (struct direntry *)((i+5L) & ~3L);
/* bump up number of entries read, insert new entry into
linked list of entries, based on alphabetic order,
scanning from head of list */
for (i = TotalEntries++; i >= 0; i--)
{
if (!(NextPtr = ThisPtr->next))
break;
if (is_alpha_lower (TmpDir, NextPtr))
break;
ThisPtr = NextPtr;
}
/* actual list insertion (ThisPtr-->NextPtr becomes
ThisPtr-->TmpDir-->NextPtr) */
TmpDir->next = NextPtr;
ThisPtr->next = TmpDir;
return (NULL);
}
else
return (IoErr() == ERROR_NO_MORE_ENTRIES) ?
(char *)(more = 0L) : "Error Reading Directory";
}
/* dedicated alphabetizing function for BrowseDir()
/* returns TRUE if first string comes before second string alphabetically,
and files always come before directories */
static is_alpha_lower (EntA, EntB)
struct direntry *EntA, *EntB;
{
register struct direntry *PtrA = EntA;
register TEXT *psA,*psB, a,b;
/* if both are files or directories... */
if (PtrA->isfile == EntB->isfile)
{
/* scan strings to determine order */
psA = &PtrA->text[0];
psB = &EntB->text[0];
while (a = *psA++)
{
if (a > (b = *psB++))
return (FALSE);
else if (a < b)
break;
}
return (TRUE);
}
/* if it got this far, one string is file, other is dir */
return (PtrA->isfile);
}
/* Display directory listing */
static DispDir()
{
register long i,new;
register long x,y;
register struct direntry *dir_entry = (struct direntry *)&ListHead;
/* scan down list to current entry pointer */
new = CurEntry;
for (i = 0; i < new; i++)
dir_entry = dir_entry->next;
y = 20L;
for (i = 0; i < DENTS; i++)
{
y += (x = 10);
names[i].NextText = NULL;
names[i].IText = "";
names[i].LeftEdge = 0;
/* if entry is in window... */
if ((new+i) < TotalEntries)
{
dir_entry = dir_entry->next;
/* print text to window depending on entry type */
names[i].IText = &dir_entry->text[0];
if (dir_entry->isfile)
PrintIText (ReqRastPort, &names[i], 10L, y);
else
{
/* if entry is a directory, put the '(dir)'
in front of it */
names[i].LeftEdge = 48;
PrintIText (ReqRastPort, &DirIText, 10L, y);
PrintIText (ReqRastPort, &names[i], 10L, y);
names[i].NextText = &DirIText;
}
x = ReqRastPort->cp_x;
}
if (x < FILLWIDTH+10)
RectFill (ReqRastPort,x,y,(long)(FILLWIDTH+10),
(long)(y+8L));
}
}
/*
pathcat()
Combines dir, plus name into dir */
pathcat (dir, file_name)
char *dir, *file_name;
{
register char *pdst = dir;
register char *psrc = file_name;
register char c = ':';
/* scan to end of 'dir' string */
while (*pdst)
c = *pdst++;
/* if it wasn't a volume spec, put a subdirectory slash on it */
if (c != ':')
*pdst++ = '/';
/* append name */
while (*pdst++ = *psrc++);
}
/* notify (win, txt) */
/* Prompts for Yes/No response */
notify (win, txt)
struct Window *win;
char *txt;
{
Note_IText.IText = txt;
AutoRequest (win, &Note_IText, 0L, &OK_IText, 0L, 0L,
(long)(IntuiTextLength (&Note_IText) + 50L), 70L);
}